#pragma once

#include <iostream>

#include <functional>
#include <thread>

#include "shared_queue.hpp"

class task_executor {
    using task = std::function<void()>;

    task_executor() = default;
    task_executor(const task_executor &) = delete;
    task_executor& operator =(const task_executor &) = delete;

    void run() {
        m_thread = std::thread([=]() {
            while(!m_stop) {
                task t = m_q.pop();
                if(t) {
                    t();
                }
            }
        });
    }

public:
    static std::unique_ptr<task_executor> create() {
        std::unique_ptr<task_executor> executor(new task_executor);
        executor->run();
        return executor;
    }

    ~task_executor() {
        post([this]() { m_stop = true; });
        if(m_thread.joinable())
            m_thread.join();
    }


    void post(task t) {
        m_q.push(t);
    }

    void clear() {
        m_q.clear();
    }

private:
    shared_queue<task> m_q;
    std::thread m_thread;
    bool m_stop = false;
};
